/*
实验9-2 两个序列的故事
分数 35
作者 翁才智
单位 浙江大学

给定两个整数序列 A=a1​,a2​,⋯,an​ 与 B=b1​,b2​,⋯,bn​, 我们称 A 中长度为 (r−l+1) 的连续子序列 al​,al+1​,⋯,ar​ (1≤l≤r≤n) 是好的，如果 min(al​,al+1​,⋯,ar​)≥br−l+1​。
对于所有 1≤k≤n 请求出 A 中是否有长度为 k 的好的连续子序列。
输入格式：

第一行输入一个整数 n (1≤n≤5×105) 表示两个序列的长度。
第二行输入 n 个整数 a1​,a2​,⋯,an​ (1≤ai​≤10^6) 表示序列 A。
第三行输入 n 个整数 b1​,b2​,⋯,bn​ (1≤bi​≤10^6) 表示序列 B。
输出格式：

在一行中输出长度为 n 的字符串 s1​s2​⋯sn​。若 A 中存在长度为 k 的好的连续子序列则 sk​=1，否则 sk​=0。
输入样例 1：

5
1 3 2 5 3
6 3 3 2 3

输出样例 1：

01010

样例解释：

对于第一组样例数据，{5,3} 是一个长度为 2 的好的连续子序列，{3,2,5,3} 是一个长度为 4 的好的连续子序列。
输入样例 2：

1
1000000
1000000

输出样例 2：

1

输入样例 3：

1
1
1000000

输出样例 3：

0
*/

/*
为了解决这个问题，我们需要判断序列 A 中是否存在长度为 k 的连续子序列，使得该子序列的最小值大于等于序列 B 中对应位置的值。
通过高效的预处理和并查集技术，我们可以在合理的时间内解决这个问题。

方法思路

    预处理左右边界：使用单调栈预处理每个元素的左右边界，确定每个元素作为最小值的最长连续子序列长度。

    排序元素：根据元素值从大到小排序，确保较大的元素优先处理。

    并查集处理区间覆盖：使用并查集结构高效处理每个元素能覆盖的区间，记录每个长度 k 的最大最小值。

    结果判断：比较每个长度 k 的最大最小值与序列 B 中的对应值，生成结果字符串。
*/

#include <bits/stdc++.h>
#include <vector>
using namespace std;

struct Element {
    int a;
    int L;
};

int main() {
    int n;
    scanf("%d", &n);
    vector<int> a(n);
    for (int i = 0; i < n; ++i) {
        scanf("%d", &a[i]);
    }
    vector<int> b(n);
    for (int i = 0; i < n; ++i) {
        scanf("%d", &b[i]);
    }

    vector<int> left(n, -1);
    stack<int> st;
    for (int i = 0; i < n; ++i) {
        while (!st.empty() && a[st.top()] >= a[i]) {
            st.pop();
        }
        if (!st.empty()) {
            left[i] = st.top();
        }
        st.push(i);
    }

    st = stack<int>();
    vector<int> right(n, n);
    for (int i = n - 1; i >= 0; --i) {
        while (!st.empty() && a[st.top()] >= a[i]) {
            st.pop();
        }
        if (!st.empty()) {
            right[i] = st.top();
        }
        st.push(i);
    }

    vector<Element> elements(n);
    for (int i = 0; i < n; ++i) {
        elements[i].a = a[i];
        elements[i].L = right[i] - left[i] - 1;
    }

    sort(elements.begin(), elements.end(), [](const Element& x, const Element& y) {
        return x.a > y.a;
    });

    vector<int> max_min(n + 2, 0);
    vector<int> parent(n + 2);
    for (int i = 1; i <= n + 1; ++i) {
        parent[i] = i;
    }

    // function<int(int)> find = [&](int x) {
    //     if (parent[x] != x) {
    //         parent[x] = find(parent[x]);
    //     }
    //     return parent[x];
    // };

    function<int(int)> find = [&](int x) {
        int root = x;
        while (parent[root] != root) {
            root = parent[root];
        }
        while (x != root) {
            int next = parent[x];
            parent[x] = root;
            x = next;
        }
        return root;
    };

    for (const auto& e : elements) {
        int L = e.L;
        if (L < 1) continue;
        int current = 1;
        while (current <= L) {
            int k = find(current);
            if (k > L) break;
            max_min[k] = e.a;
            parent[k] = k + 1;
            current = k + 1;
        }
    }

    string res(n, '0');
    for (int k = 1; k <= n; ++k) {
        if (max_min[k] >= b[k - 1]) {
            res[k - 1] = '1';
        }
    }

    printf("%s\n", res.c_str());
    return 0;
}